package com.uziot.bucket.common.util;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * 功能描述: <br>
 * 流操作工具类，用于各种流以及文件的转换操作
 *
 * @author shidt
 * @date 2019/11/11 19:39
 */
@Slf4j
public class StreamUtils {

    private final static int BUFFER_SIZE = 4096;

    /**
     * 将InputStream转换成String
     *
     * @param in InputStream
     * @return String
     */
    public static String inputStreamToString(InputStream in) {

        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE];
        String string;
        int count;
        try {
            while ((count = in.read(data, 0, BUFFER_SIZE)) != -1) {
                outStream.write(data, 0, count);
            }
        } catch (IOException e) {
            log.error("将InputStream转换成String异常！", e);
        }

        string = new String(outStream.toByteArray(), StandardCharsets.UTF_8);
        return string;
    }

    /**
     * 将String转换成InputStream
     *
     * @param in 输入流
     * @return 输出流
     */
    public static InputStream stringToInputStream(String in) {

        return new ByteArrayInputStream(in.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 将String转换成InputStream
     *
     * @param in 输入流
     * @return 字节
     */
    public static byte[] stringToByte(String in) {
        byte[] bytes = null;
        try {
            bytes = inputStreamToByte(stringToInputStream(in));
        } catch (Exception e) {
            log.error("将String转换成InputStream异常！", e);
        }
        return bytes;
    }

    /**
     * 将InputStream转换成byte数组
     *
     * @param in InputStream
     * @return byte[]
     */
    public static byte[] inputStreamToByte(InputStream in) throws IOException {

        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE];
        int count = -1;
        while ((count = in.read(data, 0, BUFFER_SIZE)) != -1) {
            outStream.write(data, 0, count);
        }

        return outStream.toByteArray();
    }

    /**
     * 将byte数组转换成InputStream
     *
     * @param in 字节
     * @return 输入流
     */
    public static InputStream byteToInputStream(byte[] in) {
        return new ByteArrayInputStream(in);
    }

    public static String byteToString(byte[] in) {
        InputStream is = null;
        try {
            is = byteToInputStream(in);
        } catch (Exception e) {
            log.error("字节转换成流异常！", e);
        }
        assert is != null;
        return inputStreamToString(is);
    }

    public static String getString(String in) {
        String is = null;
        try {
            is = byteToString(stringToByte(in));
        } catch (Exception e) {
            log.error("字节转换为字符串异常！", e);
        }
        return is;
    }

    /**
     * 根据文件路径创建文件输入流处理
     * 以字节为单位（非 unicode ）
     */
    public static FileInputStream getFileInputStream(String filepath) throws FileNotFoundException {
        return new FileInputStream(filepath);
    }

    /**
     * 根据文件对象创建文件输入流处理
     * 以字节为单位（非 unicode ）
     */
    public static FileInputStream getFileInputStream(File file) throws FileNotFoundException {
        return new FileInputStream(file);
    }

    /**
     * 根据文件对象创建文件输出流处理
     * 以字节为单位（非 unicode ）
     *
     * @param append true:文件以追加方式打开,false:则覆盖原文件的内容
     */
    public static FileOutputStream getFileOutputStream(File file, boolean append) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(file, append);
        } catch (FileNotFoundException e) {
            log.error("错误信息:文件不存在", e);
        }
        return fileOutputStream;
    }

    /**
     * 根据文件路径创建文件输出流处理
     * 以字节为单位（非 unicode ）
     *
     * @param append true:文件以追加方式打开,false:则覆盖原文件的内容
     */
    public static FileOutputStream getFileOutputStream(String filepath, boolean append) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(filepath, append);
        } catch (FileNotFoundException e) {
            log.error("错误信息:文件不存在", e);
        }
        return fileOutputStream;
    }

    public static File getFile(String filepath) {
        return new File(filepath);
    }

    public static ByteArrayOutputStream getByteArrayOutputStream() {
        return new ByteArrayOutputStream();
    }

    /**
     * Read an input stream into a string
     */
    public static String streamToString(InputStream in) throws IOException {
        StringBuilder out = new StringBuilder();
        byte[] b = new byte[4096];
        for (int n; (n = in.read(b)) != -1; ) {
            out.append(new String(b, 0, n));
        }
        return out.toString();
    }

    /**
     * Read an input stream into a byte[]
     */
    public static byte[] stream2Byte(InputStream is) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int len;
        byte[] b = new byte[1024];
        while ((len = is.read(b, 0, b.length)) != -1) {
            baos.write(b, 0, len);
        }
        return baos.toByteArray();
    }


    public static byte[] inputStream2Byte(InputStream inStream) throws Exception {
        int count = 0;
        while (count == 0) {
            count = inStream.available();
        }
        byte[] b = new byte[count];
        int read = inStream.read(b);
        return b;
    }

    /**
     * @return InputStream
     */
    public static InputStream byte2InputStream(byte[] b) {
        return new ByteArrayInputStream(b);
    }

    /**
     * 将流另存为文件
     */
    public static void streamSaveAsFile(InputStream is, File outfile) {
        try (FileOutputStream fos = new FileOutputStream(outfile)) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) > 0) {
                fos.write(buffer, 0, len);
            }

        } catch (IOException e) {
            log.error("文件写入异常！", e);
            throw new RuntimeException(e);
        }
    }

    public byte[] getBytes(InputStream is) throws IOException {
        ByteArrayOutputStream byteArr = new ByteArrayOutputStream();
        byte[] b = new byte[BUFFER_SIZE];
        int len;

        while ((len = is.read(b, 0, BUFFER_SIZE)) != -1) {
            byteArr.write(b, 0, len);
        }
        byteArr.flush();
        return byteArr.toByteArray();
    }

    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                log.error("关闭流异常！", e);
            }
        }
    }

    public static void close(InputStream inputStream, OutputStream outputStream) {
        close(inputStream);
        close(outputStream);
    }

    public static void close(OutputStream outputStream, InputStream inputStream) {
        close(inputStream);
        close(outputStream);
    }

    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));

    }
}